home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Applications / Python 1.3 / Python 1.3 PPC / Lib / mac / FrameWork.py < prev    next >
Encoding:
Python Source  |  1995-10-11  |  15.6 KB  |  628 lines  |  [TEXT/PYTH]

  1. "A sort of application framework for the Mac"
  2.  
  3. DEBUG=0
  4.  
  5. import MacOS
  6. import traceback
  7.  
  8. from addpack import addpack
  9. addpack('Tools')
  10. addpack('bgen')
  11. addpack('ae')
  12. addpack('ctl')
  13. addpack('dlg')
  14. addpack('evt')
  15. addpack('menu')
  16. addpack('qd')
  17. #addpack('res')
  18. #addpack('snd')
  19. addpack('win')
  20.  
  21. from AE import *
  22. from AppleEvents import *
  23. from Ctl import *
  24. from Controls import *
  25. from Dlg import *
  26. from Dialogs import *
  27. from Evt import *
  28. from Events import *
  29. from Menu import *
  30. from Menus import *
  31. from Qd import *
  32. from QuickDraw import *
  33. #from Res import *
  34. #from Resources import *
  35. #from Snd import *
  36. #from Sound import *
  37. from Win import *
  38. from Windows import *
  39.  
  40. import EasyDialogs
  41.  
  42. kHighLevelEvent = 23    # Don't know what header file this should come from
  43.  
  44.  
  45. # Map event 'what' field to strings
  46. eventname = {}
  47. eventname[1] = 'mouseDown'
  48. eventname[2] = 'mouseUp'
  49. eventname[3] = 'keyDown'
  50. eventname[4] = 'keyUp'
  51. eventname[5] = 'autoKey'
  52. eventname[6] = 'updateEvt'
  53. eventname[7] = 'diskEvt'
  54. eventname[8] = 'activateEvt'
  55. eventname[15] = 'osEvt'
  56. eventname[23] = 'kHighLevelEvent'
  57.  
  58. # Map part codes returned by WhichWindow() to strings
  59. partname = {}
  60. partname[0] = 'inDesk'
  61. partname[1] = 'inMenuBar'
  62. partname[2] = 'inSysWindow'
  63. partname[3] = 'inContent'
  64. partname[4] = 'inDrag'
  65. partname[5] = 'inGrow'
  66. partname[6] = 'inGoAway'
  67. partname[7] = 'inZoomIn'
  68. partname[8] = 'inZoomOut'
  69.  
  70. # A rectangle that's bigger than the screen,
  71. # but not so big that adding the screen size to it will cause 16-bit overflow
  72. everywhere = (-16000, -16000, 16000, 16000)
  73.  
  74.  
  75. class Application:
  76.     
  77.     "Application framework -- your application should be a derived class"
  78.     
  79.     def __init__(self):
  80.         self._windows = {}
  81.         self.makemenubar()
  82.     
  83.     def makemenubar(self):
  84.         self.menubar = MenuBar()
  85.         AppleMenu(self.menubar, self.getabouttext(), self.do_about)
  86.         self.makeusermenus()
  87.         
  88.     def appendwindow(self, wid, window):
  89.         self._windows[wid] = window
  90.         
  91.     def removewindow(self, wid):
  92.         del self._windows[wid]
  93.     
  94.     def getabouttext(self):
  95.         return "About %s..." % self.__class__.__name__
  96.     
  97.     def do_about(self, id, item, window, event):
  98.         EasyDialogs.Message("Hello, world!" + "\015(%s)" % self.__class__.__name__)
  99.     
  100.     # The main event loop is broken up in several simple steps.
  101.     # This is done so you can override each individual part,
  102.     # if you have a need to do extra processing independent of the
  103.     # event type.
  104.     # Normally, however, you'd just define handlers for individual
  105.     # events.
  106.     # (XXX I'm not sure if using default parameter values is the right
  107.     # way to define the mask and wait time passed to WaitNextEvent.)
  108.     
  109.     def mainloop(self, mask = everyEvent, wait = 0):
  110.         saveyield = MacOS.EnableAppswitch(self.yield)
  111.         try:
  112.             while 1:
  113.                 try:
  114.                     self.do1event(mask, wait)
  115.                 except (Application, SystemExit):
  116.                     break
  117.         finally:
  118.             MacOS.EnableAppswitch(saveyield)
  119.     
  120.     yield = -1
  121.     
  122.     def do1event(self, mask = everyEvent, wait = 0):
  123.         ok, event = self.getevent(mask, wait)
  124.         if IsDialogEvent(event):
  125.             if self.do_dialogevent(event):
  126.                 return
  127.         if ok:
  128.             self.dispatch(event)
  129.     
  130.     def getevent(self, mask = everyEvent, wait = 0):
  131.         ok, event = WaitNextEvent(mask, wait)
  132.         return ok, event
  133.             
  134.     def dispatch(self, event):
  135.         (what, message, when, where, modifiers) = event
  136.         if eventname.has_key(what):
  137.             name = "do_" + eventname[what]
  138.         else:
  139.             name = "do_%d" % what
  140.         try:
  141.             handler = getattr(self, name)
  142.         except AttributeError:
  143.             handler = self.do_unknownevent
  144.         handler(event)
  145.         
  146.     def do_dialogevent(self, event):
  147.         gotone, window, item = DialogSelect(event)
  148.         if gotone:
  149.             if self._windows.has_key(window):
  150.                 self._windows[window].do_itemhit(item, event)
  151.             else:
  152.                 print 'Dialog event for unknown dialog'
  153.             return 1
  154.         return 0
  155.     
  156.     def do_mouseDown(self, event):
  157.         (what, message, when, where, modifiers) = event
  158.         partcode, wid = FindWindow(where)
  159.  
  160.         #
  161.         # Find the correct name.
  162.         #
  163.         if partname.has_key(partcode):
  164.             name = "do_" + partname[partcode]
  165.         else:
  166.             name = "do_%d" % partcode
  167.  
  168.         if wid == None:
  169.             # No window, or a non-python window    
  170.             try:
  171.                 handler = getattr(self, name)
  172.             except AttributeError:
  173.                 # Not menubar or something, so assume someone
  174.                 # else's window
  175.                 MacOS.HandleEvent(event)
  176.                 return        
  177.         elif self._windows.has_key(wid):
  178.             # It is a window. Hand off to correct window.
  179.             window = self._windows[wid]
  180.             try:
  181.                 handler = getattr(window, name)
  182.             except AttributeError:
  183.                 handler = self.do_unknownpartcode
  184.         else:
  185.             # It is a python-toolbox window, but not ours.
  186.             handler = self.do_unknownwindow
  187.         handler(partcode, wid, event)
  188.  
  189.     def do_inSysWindow(self, partcode, window, event):
  190.         MacOS.HandleEvent(event)
  191.     
  192.     def do_inDesk(self, partcode, window, event):
  193.         MacOS.HandleEvent(event)
  194.     
  195.     def do_inMenuBar(self, partcode, window, event):
  196.         (what, message, when, where, modifiers) = event
  197.         result = MenuSelect(where)
  198.         id = (result>>16) & 0xffff    # Hi word
  199.         item = result & 0xffff        # Lo word
  200.         self.do_rawmenu(id, item, window, event)
  201.     
  202.     def do_rawmenu(self, id, item, window, event):
  203.         try:
  204.             self.do_menu(id, item, window, event)
  205.         finally:
  206.             HiliteMenu(0)
  207.     
  208.     def do_menu(self, id, item, window, event):
  209.         self.menubar.dispatch(id, item, window, event)
  210.     
  211.     
  212.     def do_unknownpartcode(self, partcode, window, event):
  213.         (what, message, when, where, modifiers) = event
  214.         if DEBUG: print "Mouse down at global:", where
  215.         if DEBUG: print "\tUnknown part code:", partcode
  216.         if DEBUG: print "\tEvent:", self.printevent(event)
  217.         MacOS.HandleEvent(event)
  218.         
  219.     def do_unknownwindow(self, partcode, window, event):
  220.         if DEBUG: print 'Unknown window:', window
  221.         MacOS.HandleEvent(event)
  222.     
  223.     def do_keyDown(self, event):
  224.         self.do_key(event)
  225.     
  226.     def do_autoKey(self, event):
  227.         if not event[-1] & cmdKey:
  228.             self.do_key(event)
  229.     
  230.     def do_key(self, event):
  231.         (what, message, when, where, modifiers) = event
  232.         c = chr(message & charCodeMask)
  233.         if modifiers & cmdKey:
  234.             if c == '.':
  235.                 raise self
  236.             else:
  237.                 result = MenuKey(ord(c))
  238.                 id = (result>>16) & 0xffff    # Hi word
  239.                 item = result & 0xffff        # Lo word
  240.                 if id:
  241.                     self.do_rawmenu(id, item, None, event)
  242. #                elif c == 'w':
  243. #                    w = FrontWindow()
  244. #                    if w:
  245. #                        self.do_close(w)
  246. #                    else:
  247. #                        if DEBUG: print 'Command-W without front window'
  248.                 else:
  249.                     if DEBUG: print "Command-" +`c`
  250.         else:
  251.             # See whether the front window wants it
  252.             w = FrontWindow()
  253.             if w and self._windows.has_key(w):
  254.                 window = self._windows[w]
  255.                 try:
  256.                     do_char = window.do_char
  257.                 except AttributeError:
  258.                     do_char = self.do_char
  259.             do_char(c, event)
  260.     
  261.     def do_char(self, c, event):
  262.         if DEBUG: print "Character", `c`
  263.     
  264.     def do_updateEvt(self, event):
  265.         (what, message, when, where, modifiers) = event
  266.         wid = WhichWindow(message)
  267.         if wid and self._windows.has_key(wid):
  268.             window = self._windows[wid]
  269.             window.do_rawupdate(wid, event)
  270.         else:
  271.             MacOS.HandleEvent(event)
  272.     
  273.     def do_activateEvt(self, event):
  274.         (what, message, when, where, modifiers) = event
  275.         wid = WhichWindow(message)
  276.         if wid and self._windows.has_key(wid):
  277.             window = self._windows[wid]
  278.             window.do_activate(modifiers & 1, event)
  279.         else:
  280.             MacOS.HandleEvent(event)
  281.             
  282.     def do_osEvt(self, event):
  283.         (what, message, when, where, modifiers) = event
  284.         which = (message >> 24) & 0xff
  285.         if which == 1:    # suspend/resume
  286.             self.do_suspendresume(event)
  287.         else:
  288.             if DEBUG:
  289.                 print 'unknown osEvt:',
  290.                 self.printevent(event)
  291.                 
  292.     def do_suspendresume(self, event):
  293.         # Is this a good idea???
  294.         (what, message, when, where, modifiers) = event
  295.         w = FrontWindow()
  296.         if w:
  297.             nev = (activateEvt, w, when, where, message&1)
  298.             self.do_activateEvt(self, nev)
  299.  
  300.     def do_kHighLevelEvent(self, event):
  301.         (what, message, when, where, modifiers) = event
  302.         if DEBUG: 
  303.             print "High Level Event:",
  304.             self.printevent(event)
  305.         try:
  306.             AEProcessAppleEvent(event)
  307.         except:
  308.             print "AEProcessAppleEvent error:"
  309.             traceback.print_exc()
  310.     
  311.     def do_unknownevent(self, event):
  312.         if DEBUG:
  313.             print "Unhandled event:",
  314.             self.printevent(event)
  315.     
  316.     def printevent(self, event):
  317.         (what, message, when, where, modifiers) = event
  318.         nicewhat = `what`
  319.         if eventname.has_key(what):
  320.             nicewhat = eventname[what]
  321.         print nicewhat,
  322.         if what == kHighLevelEvent:
  323.             h, v = where
  324.             print `ostypecode(message)`, hex(when), `ostypecode(h | (v<<16))`,
  325.         else:
  326.             print hex(message), hex(when), where,
  327.         print hex(modifiers)
  328.  
  329.  
  330. class MenuBar:
  331.     """Represent a set of menus in a menu bar.
  332.     
  333.     Interface:
  334.     
  335.     - (constructor)
  336.     - (destructor)
  337.     - addmenu
  338.     - addpopup (normally used internally)
  339.     - dispatch (called from Application)
  340.     """
  341.     
  342.     nextid = 1    # Necessarily a class variable
  343.     
  344.     def getnextid(self):
  345.         id = self.nextid
  346.         self.nextid = id+1
  347.         return id
  348.     
  349.     def __init__(self):
  350.         ClearMenuBar()
  351.         self.bar = GetMenuBar()
  352.         self.menus = {}
  353.     
  354.     def addmenu(self, title, after = 0):
  355.         id = self.getnextid()
  356.         m = NewMenu(id, title)
  357.         m.InsertMenu(after)
  358.         DrawMenuBar()
  359.         return id, m
  360.     
  361.     def addpopup(self, title = ''):
  362.         return self.addmenu(title, -1)
  363.     
  364.     def install(self):
  365.         self.bar.SetMenuBar()
  366.         DrawMenuBar()
  367.     
  368.     def dispatch(self, id, item, window, event):
  369.         if self.menus.has_key(id):
  370.             self.menus[id].dispatch(id, item, window, event)
  371.         else:
  372.             if DEBUG: print "MenuBar.dispatch(%d, %d, %s, %s)" % \
  373.                 (id, item, window, event)
  374.     
  375.  
  376. # XXX Need a way to get menus as resources and bind them to callbacks
  377.  
  378. class Menu:
  379.     "One menu."
  380.     
  381.     def __init__(self, bar, title, after=0):
  382.         self.bar = bar
  383.         self.id, self.menu = self.bar.addmenu(title, after)
  384.         bar.menus[self.id] = self
  385.         self.items = []
  386.     
  387.     def additem(self, label, shortcut=None, callback=None, kind=None):
  388.         self.menu.AppendMenu('x')        # add a dummy string
  389.         self.items.append(label, shortcut, callback, kind)
  390.         item = len(self.items)
  391.         self.menu.SetMenuItemText(item, label)        # set the actual text
  392.         if shortcut:
  393.             self.menu.SetItemCmd(item, ord(shortcut))
  394.         return item
  395.     
  396.     def addcheck(self, label, shortcut=None, callback=None):
  397.         return self.additem(label, shortcut, callback, 'check')
  398.     
  399.     def addradio(self, label, shortcut=None, callback=None):
  400.         return self.additem(label, shortcut, callback, 'radio')
  401.     
  402.     def addseparator(self):
  403.         self.menu.AppendMenu('(-')
  404.         self.items.append('', None, None, 'separator')
  405.     
  406.     def addsubmenu(self, label, title=''):
  407.         sub = Menu(self.bar, title, -1)
  408.         item = self.additem(label, '\x1B', None, 'submenu')
  409.         self.menu.SetItemMark(item, sub.id)
  410.         return sub
  411.     
  412.     def dispatch(self, id, item, window, event):
  413.         title, shortcut, callback, type = self.items[item-1]
  414.         if callback:
  415.             callback(id, item, window, event)
  416.  
  417.  
  418. class MenuItem:
  419.     def __init__(self, menu, title, shortcut=None, callback=None, kind=None):
  420.         self.item = menu.additem(title, shortcut, callback)
  421.  
  422. class RadioItem(MenuItem):
  423.     def __init__(self, menu, title, shortcut=None, callback=None):
  424.         MenuItem.__init__(self, menu, title, shortcut, callback, 'radio')
  425.  
  426. class CheckItem(MenuItem):
  427.     def __init__(self, menu, title, shortcut=None, callback=None):
  428.         MenuItem.__init__(self, menu, title, shortcut, callback, 'check')
  429.  
  430. def Separator(menu):
  431.     menu.addseparator()
  432.  
  433. def SubMenu(menu, label, title=''):
  434.     return menu.addsubmenu(label, title)
  435.  
  436.  
  437. class AppleMenu(Menu):
  438.     
  439.     def __init__(self, bar, abouttext="About me...", aboutcallback=None):
  440.         Menu.__init__(self, bar, "\024")
  441.         self.additem(abouttext, None, aboutcallback)
  442.         self.addseparator()
  443.         self.menu.AppendResMenu('DRVR')
  444.     
  445.     def dispatch(self, id, item, window, event):
  446.         if item == 1:
  447.             Menu.dispatch(self, id, item, window, event)
  448.         else:
  449.             name = self.menu.GetItem(item)
  450.             OpenDeskAcc(name)
  451.  
  452. class Window:
  453.     """A single window belonging to an application"""
  454.     
  455.     def __init__(self, parent):
  456.         self.wid = None
  457.         self.parent = parent
  458.         
  459.     def open(self):
  460.         self.wid = NewWindow((40, 40, 400, 400), self.__class__.__name__, 1,
  461.                 0, -1, 1, 0)
  462.         self.do_postopen()
  463.         
  464.     def do_postopen(self):
  465.         """Tell our parent we exist"""
  466.         self.parent.appendwindow(self.wid, self)
  467.         
  468.     def close(self):
  469.         pass
  470.         self.do_postclose()
  471.             
  472.     def do_postclose(self):
  473.         self.parent.removewindow(self.wid)
  474.         self.parent = None
  475.         self.wid = None
  476.     
  477.     def do_inDrag(self, partcode, window, event):
  478.         where = event[3]
  479.         window.DragWindow(where, self.draglimit)
  480.     
  481.     draglimit = everywhere
  482.     
  483.     def do_inGoAway(self, partcode, window, event):
  484.         where = event[3]
  485.         if window.TrackGoAway(where):
  486.             self.close()
  487.     
  488.     def do_inZoom(self, partcode, window, event):
  489.         (what, message, when, where, modifiers) = event
  490.         if window.TrackBox(where, partcode):
  491.             window.ZoomWindow(partcode, 1)
  492.     
  493.     def do_inZoomIn(self, partcode, window, event):
  494.         SetPort(window) # !!!
  495.         self.do_inZoom(partcode, window, event)
  496.     
  497.     def do_inZoomOut(self, partcode, window, event):
  498.         SetPort(window) # !!!
  499.         self.do_inZoom(partcode, window, event)
  500.     
  501.     def do_inGrow(self, partcode, window, event):
  502.         (what, message, when, where, modifiers) = event
  503.         result = window.GrowWindow(where, self.growlimit)
  504.         if result:
  505.             height = (result>>16) & 0xffff    # Hi word
  506.             width = result & 0xffff        # Lo word
  507.             self.do_resize(width, height, window)
  508.     
  509.     growlimit = everywhere
  510.     
  511.     def do_resize(self, width, height, window):
  512.         window.SizeWindow(width, height, 0)
  513.         self.do_postresize(width, height, window)
  514.     
  515.     def do_postresize(self, width, height, window):
  516.         SetPort(window)
  517.         InvalRect(everywhere)
  518.     
  519.     def do_inContent(self, partcode, window, event):
  520.         #
  521.         # If we're not frontmost, select ourselves and wait for
  522.         # the activate event.
  523.         #
  524.         if FrontWindow() <> window:
  525.             window.SelectWindow()
  526.             return
  527.         # We are. Handle the event.
  528.         (what, message, when, where, modifiers) = event
  529.         SetPort(window)
  530.         local = GlobalToLocal(where)
  531.         self.do_contentclick(local, modifiers, event)
  532.         
  533.     def do_contentclick(self, local, modifiers, event):
  534.         print 'Click in contents at %s, modifiers %s'%(local, modifiers)
  535.     
  536.     def do_rawupdate(self, window, event):
  537.         if DEBUG: print "raw update for", window
  538.         window.BeginUpdate()
  539.         self.do_update(window, event)
  540.         window.EndUpdate()
  541.     
  542.     def do_update(self, window, event):
  543.         EraseRect(everywhere)
  544.         
  545.     def do_activate(self, activate, event):
  546.         if DEBUG: print 'Activate %d for %s'%(activate, self.wid)
  547.         
  548. class ControlsWindow(Window):
  549.  
  550.     def do_rawupdate(self, window, event):
  551.         if DEBUG: print "raw update for", window
  552.         window.BeginUpdate()
  553.         self.do_update(window, event)
  554.         DrawControls(window)
  555.         window.DrawGrowIcon()
  556.         window.EndUpdate()
  557.     
  558.     def do_controlhit(self, window, control, pcode, event):
  559.         if DEBUG: print "control hit in", window, "on", control, "; pcode =", pcode
  560.  
  561.     def do_inContent(self, partcode, window, event):
  562.         (what, message, when, where, modifiers) = event
  563.         local = GlobalToLocal(where)
  564.         ctltype, control = FindControl(local, window)
  565.         if ctltype and control:
  566.             pcode = control.TrackControl(local)
  567.             if pcode:
  568.                 self.do_controlhit(window, control, pcode, event)
  569.         else:
  570.             if DEBUG: print "FindControl(%s, %s) -> (%s, %s)" % \
  571.                 (local, window, ctltype, control)
  572.     
  573. class DialogWindow(Window):
  574.     """A modeless dialog window"""
  575.     
  576.     def open(self, resid):
  577.         self.wid = GetNewDialog(resid, -1)
  578.         self.do_postopen()
  579.         
  580.     def close(self):
  581.         self.do_postclose()
  582.         
  583.     def do_itemhit(self, item, event):
  584.         print 'Dialog %s, item %d hit'%(self.wid, item)
  585.         
  586.     def do_rawupdate(self, window, event):
  587.         pass
  588.  
  589. def ostypecode(x):
  590.     "Convert a long int to the 4-character code it really is"
  591.     s = ''
  592.     for i in range(4):
  593.         x, c = divmod(x, 256)
  594.         s = chr(c) + s
  595.     return s
  596.  
  597.  
  598. class TestApp(Application):
  599.     
  600.     "This class is used by the test() function"
  601.     
  602.     def makeusermenus(self):
  603.         self.filemenu = m = Menu(self.menubar, "File")
  604.         self.saveitem = MenuItem(m, "Save", "S", self.save)
  605.         Separator(m)
  606.         self.optionsmenu = mm = SubMenu(m, "Options")
  607.         self.opt1 = CheckItem(mm, "Arguments")
  608.         self.opt2 = CheckItem(mm, "Being hit on the head lessons")
  609.         self.opt3 = CheckItem(mm, "Complaints")
  610.         Separator(m)
  611.         self.quititem = MenuItem(m, "Quit", "Q", self.quit)
  612.     
  613.     def save(self, *args):
  614.         print "Save"
  615.     
  616.     def quit(self, *args):
  617.         raise self
  618.  
  619.  
  620. def test():
  621.     "Test program"
  622.     app = TestApp()
  623.     app.mainloop()
  624.  
  625.  
  626. if __name__ == '__main__':
  627.     test()
  628.